package cn.ichiva.dl.tushare.analy.impl;

import cn.ichiva.common.DateUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * 交易
 */
@Slf4j
@Getter
@Setter
public class Trade implements Serializable {

    /**
     * 初始资金
     */
    private double initMoney;

    /**
     * 当前资金
     */
    private double money;

    private LinkedList<Record> tradeRecord = new LinkedList<>();
    /**
     * 购买记录
     */
    private LinkedList<Record> buyRecord = new LinkedList<>();

    private int nStock = 0;

    public double getVal(double price){
        return money + nStock * price;
    }

    //虚买
    private int vBuy = 0;

    public Trade(){
        initMoney = 100000;
        money = initMoney;
    }

    public void opt(String day,double price,int opt){
        if(-1 == opt) sell(day,price);
        else if(1 == opt)buy(day,price);
        else waitAndSee(day,price);
    }

    /**
     * 观望
     * @param price
     */
    public void waitAndSee(String day,double price) {
        Record record = new Record();
        record.setState(0);
        record.setPrice(price);
        record.setDay(day);
        record.setNStock(getNStock());
        record.setMoney(getMoney());
        record.setFaceMoney(getSurfaceMoney(price));
        tradeRecord.addLast(record);
        if(log.isTraceEnabled()){
            log.trace("观望 price = {}",price);
        }
    }

    public double getSurfaceMoney(double price){
        return nStock * price + money;
    }

    /**
     * 买入
     * @param price 买入价格
     * @return 实际买入金额
     */
    public double buy(String day,double price){
        double money = initMoney / 10D;

        Record record = new Record();
        record.setDay(day);
        double res;

        int n = 100 * (int) (money / price / 100);
        double m = n * price;
        //手续费
        double m1 = m * 0.003;
        if(m1 < 5) m1 = 5;

        if(this.money >= money && n > 0){
            m += m1;
            nStock += n;
            this.money -= m;

            record.setPrice(price);
            record.setNumber(n);
            record.setState(1);
            record.setCommission(m1);
            this.buyRecord.add(record);

            if(log.isTraceEnabled()){
                log.trace("买入 price = {}, number = {}",price,n);
            }
            res = m;
        }else {
            this.vBuy++;
            record.setPrice(price);
            record.setNumber(0);    //虚买
            record.setState(2);

            if(log.isTraceEnabled()){
                log.trace("虚买 price = {}",price);
            }
            res = 0;
        }
        record.setNStock(getNStock());
        record.setMoney(getMoney());
        record.setFaceMoney(getSurfaceMoney(price));
        this.tradeRecord.addLast(record);
        return res;
    }

    /**
     * 卖出
     * @param price 卖出价格
     * @return 实际卖出金额
     */
    public double sell(String day,double price){
        double money = initMoney / 10D;

        Record record = new Record();
        record.setDay(day);
        double res;

        if(this.vBuy > 0){
            this.vBuy--;
            record.setPrice(price);
            record.setState(-2);
            if(log.isTraceEnabled()){
                log.trace("虚卖 price = {}",price);
            }
            res = 0;
        }else {
            if(nStock > 0){
                int n = 100 * (int) (money / price / 100);
                int nPlan = n;
                Iterator<Record> it = buyRecord.iterator();

                double m = 0;
                //应税
                double mTax = 0;
                while (it.hasNext()) {
                    Record next = it.next();
                    it.remove();

                    int nRecord = next.getNumber();
                    double mRecord = nRecord * price;
                    m+= mRecord;
                    n -= nRecord;

                    long nextTime = DateUtils.toDate(next.getDay(), DateUtils.FORMAT_SMART_DD).getTime();
                    long time = DateUtils.toDate(day, DateUtils.FORMAT_SMART_DD).getTime();
                    if(nextTime + 365D * 24 * 3600 * 1000 > time){
                        //
                        double tmp = (price - next.getPrice()) * nRecord;
                        if(tmp > 0){
                            mTax += tmp;
                        }
                    }

                    if(n <= 0) break;
                }

                n = nPlan - n;
                double tax = mTax * 0.2;
                //实际卖出数量
                //手续费(包含印花税等)
                double m1 = m * 0.003;
                double m2 = m - tax - m1;

                this.money += m2;
                this.nStock -= n;

                record.setNumber(n);
                record.setCommission(m1);
                record.setTax(tax);
                record.setPrice(price);
                record.setState(-1);
                if(log.isTraceEnabled()){
                    log.trace("卖出 price = {}, number = {}",price,n);
                }
                res = m2;
            }else {
                record.setPrice(price);
                record.setState(-3);
                if(log.isTraceEnabled()){
                    log.trace("没得卖 price = {}",price);
                }
                res = 0;
            }
        }
        record.setNStock(getNStock());
        record.setMoney(getMoney());
        record.setFaceMoney(getSurfaceMoney(price));
        this.tradeRecord.addLast(record);
        return res;
    }
}
